// ==UserScript==
// @name         AI风月
// @namespace    http://tampermonkey.net/
// @version      2024-10-10
// @description  try to take over the world!
// @author       You
// @match        http*://aiporn.tw/**
// @match        http*://aifuck.cc/**
// @match        http*://acepro.store/**
// @noframes
// @icon         https://www.google.com/s2/favicons?sz=64&domain=aifuck.cc
// @require      https://cdn.jsdelivr.net/npm/@cemalgnlts/mailjs@3.0.0/dist/mailjs.min.js
// @grant        unsafeWindow
// @grant        GM_addStyle
// ==/UserScript==

/* @grant        GM_setValue
   @grant        GM_getValue
   @grant        GM_deleteValue */
/* @require      https://cdn.jsdelivr.net/gh/cemalgnlts/Mailjs@3.0.0/eventsource.min.js*/

(() => {
    'use strict';

    const {document, console} = unsafeWindow;
    const $ = (sel, src = document) => src.querySelector(sel);
    const $_ = (sel, src = document) => src.querySelectorAll(sel);
    const $$ = (path, src = document) => document.evaluate(path, src).iterateNext();
    const $$_ = (tag, cont, exact = true, src = document) => $$(
        (cont = JSON.stringify(cont), exact ? `.//${tag}[text()=${cont}]` : `.//${tag}[contains(text(),${cont})]`)
    , src);
    const maxErrLen = 200;
    const menuZ = 30, modalZ = 2000;
    const menu_border = '#999';

    if (!document.head.querySelector('meta[content*="ai风月" i]')) return;

    GM_addStyle(
`.my-highlight-L58629 {
    border: solid ${menu_border} 2px; border-radius: 0.5em;
    box-shadow: 0 0 4px 0 #999;
}
#my-menu-X71368 {
    position: fixed; top: 1em; left: 1em;
    background-color: white;
    z-index: ${menuZ};
}
#my-menu-X71368 > summary{
    /*height: 2em;
    line-height: 2em;*/
    direction: rtl;
}
#my-menu-X71368 > * {
    cursor: pointer;
    padding: 0.5em 1em;
    text-align: center;
}
#my-menu-X71368 > *:last-child{ color: red; }
#my-menu-X71368[open] > summary{ width: 100%; }
#my-menu-X71368[open] > *:not(:last-child){ border-bottom: solid ${menu_border} 1px; }
#my-mask-T90346 {
    height: 100vh; width: 100vw;
    position: fixed; top: 0; left: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: ${modalZ};
}
#my-modal-W60837 {
    height: 90%; width: 90%;
    position: fixed; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    background: white;
    display: flex;
    flex-direction: column;
    z-index: ${modalZ+menuZ};
}
#my-modal-W60837 > div {
    height: 40px;
    background: #f0f0f0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 10px;
    border-top-left-radius: inherit;
    border-top-right-radius: inherit;
    border-bottom: 1px solid #ccc;
}
#my-modal-W60837 > div) > div {
    display: flex;
    gap: 10px;
}
#my-modal-W60837 > div button {
    padding: 5px 10px;
    cursor: pointer;
}
#my-modal-W60837 > div > button {
    color: red;
}
#my-modal-W60837 > iframe {
    flex: 1;
    width: 100%;
    border: none;
    border-bottom-left-radius: inherit;
    border-bottom-right-radius: inherit;
}`);
    /*GM_addStyle(`
    #my-prompt-V24082{
        position: fixed; top: 0; left: 0;
        width: 100%; height: 100%;
        background: rgba(0,0,0,0.5);
        display: flex; justify-content: center; align-items: center;
        z-index: ${modalZ};
    }
    #my-prompt-V24082 > div{
        background: white;
        padding: 20px;
        border-radius: 5px;
        width: 80%;
        max-width: 500px;
    }
    #my-prompt-V24082 textarea{
        width: 100%; height: 150px;
        margin: 10px 0;
        border: 1px solid #ccc; border-radius: 4px;
        padding: 8px 12px;
        box-sizing: border-box;
    }
    #my-prompt-V24082 button {
        border: 1px solid #ccc; border-radius: 4px;
        padding: revert;
        cursor: pointer;
        background-color: #f0f0f0;
        transition: background-color 0.2s;
    }
    #my-prompt-V24082 button:hover { background-color: #e0e0e0; }
    #my-prompt-V24082 button:active { background-color: #d0d0d0; }
    `);*/

    const modifyInput = (elem, txt, append = false, src = document) => {
        elem.focus();
        if (!append) src.execCommand('selectAll', false);
        src.execCommand('insertText', false, txt);
        elem.blur();
    };
    const genStr = (minl, maxl) => {
        const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        const length = Math.floor(Math.random() * (maxl - minl + 1)) + minl;
        return Array.from({ length }, () => charset[Math.floor(Math.random() * charset.length)]).join('');
    };
    const waitFor = ms => new Promise((res) => setTimeout(res, ms));
    const waitUntil = async (ms, pred, post = true) => {
        do await waitFor(ms); while(!await Promise.resolve(pred()));
        if (post) await waitFor(ms);
    };
    const showErr = err => {
        let msg = err.toString();
        msg = msg.slice(0, maxErrLen) + (msg.length > maxErrLen ? '...' : '');
        alert('Some error has occured. Message:\n' + msg);
        console.error(err);
    };
    const makeExclusive = f => (() => {
        let flag = false;
        return async (...args) => {
            if (flag) {
                alert("该功能正在运行中！");
            } else {
                flag = true;
                try { await Promise.resolve(f(...args)); }
                finally { flag = false; }
            }
        };
    })();
    /*
    const multilinePrompt = (() => {
        const modal = document.createElement('div');
        modal.id = 'my-prompt-V24082';
        //modal.style.cssText = ``;
        const ori_dis = modal.style.display;
        modal.style.display = 'none';
        const content = document.createElement('div');
        //content.style.cssText = 'background:white;padding:20px;border-radius:5px;width:80%;max-width:500px;';
        const title = document.createElement('p');
        const textarea = document.createElement('textarea');
        //textarea.style.cssText = `width: 100%; height: 150px; margin: 10px 0; padding: revert;`;
        const btnContainer = document.createElement('div');
        btnContainer.style.textAlign = 'right';
        const okBtn = document.createElement('button');
        okBtn.textContent = '确定';
        const cancelBtn = document.createElement('button');
        cancelBtn.textContent = '取消';
        btnContainer.appendChild(cancelBtn);
        btnContainer.appendChild(okBtn);
        content.appendChild(title);
        content.appendChild(textarea);
        content.appendChild(btnContainer);
        modal.appendChild(content);
        document.body.appendChild(modal);
        return (msg, defaultVal = '') => new Promise((resolve) => {
            title.textContent = msg;
            textarea.value = defaultVal;
            okBtn.onclick = () => { resolve(textarea.value); };
            cancelBtn.onclick = () => { resolve(null); };
            modal.style.display = ori_dis;
            textarea.focus();
        }).finally(() => { modal.style.display = 'none'; });
    })();
    */
    const readFromLocal = () => {
        const input = document.createElement('input');
        input.type = 'file';
        input.style.display = 'none';
        document.body.appendChild(input);
        return new Promise((resolve) => {
            input.addEventListener('change', () => { resolve(input?.files[0]?.text() ?? null); });
            input.click();
        }).finally(() => { input.remove(); });
    };

    const regAccount = makeExclusive(async () => {
        const Iname = () => $('input#name');
        const Iemail = () => $('input#email');
        const Ipsw = () => $('input#password');
        const Icode = () => $('input#code');
        const Bsend = () => $$_('button', "发送验证码");
        const Bsubmit = () => $$_('button', "注册");
        //console.log(Bsend);
        //console.log(Bsubmit);
        const mailjs = await new Mailjs();
        try {
            //if (!(Iname && Iemail && Ipsw && Icode && Bsend && Bsubmit)) throw {myerr: true};
            const name = genStr(12, 16);
            modifyInput(Iname(), name);
            const {username: email, password: psw} = await
                mailjs.createOneAccount()
                  .then(res => {
                      if (!res.status) throw new Error('Failed to create email account');
                      return res.data;
                  })
            ;
            modifyInput(Iemail(), email);
            modifyInput(Ipsw(), psw + '1');
            await waitFor(500);
            Bsend().click();
            let code;
            //Registration Succeeded
            await waitUntil(2500, async () => ((code = (await mailjs.getMessages())?.data[0]?.intro) != undefined), false);
            code = /\d{6}/.exec(code)[0];
            /*
            const code = await new Promise((resolve, reject) => {
                let tmOut;
                const fin = () => { mailjs.off(); clearTimeout(tmOut); };
                tmOut = setTimeout(() => { fin(); console.log('timeout'); reject(new Error('Get code timeout')); }, 30e3);
                mailjs.on('arrive', msg => { fin(); console.log(msg); resolve(/\d{6}/.exec(msg.intro)[0]); });
                mailjs.on('error', err => { fin(); console.log(err); reject(err); });
                console.log('event listener registered')
                Bsend.click();
            }).finally(() => { mailjs.deleteMe(); });
            */
            modifyInput(Icode(), code);
            Bsubmit().click();
        }
        catch(err) { showErr(err); }
        finally{ mailjs.deleteMe(); }
    });

    // let hist = GM_getValue('chat_history', null);

    /*const clearVar = (ext = false) => {
        if (ext && !confirm('确定取消导入?')) return;
        GM_deleteValue('chat_history');
        // GM_deleteValue('chat-history');
        GM_deleteValue('chat_title');
        if (ext) alert('已取消导入');
    };*/
    const createModal = url => {
        const modal = document.createElement('div');
        modal.className = 'my-highlight-L58629';
        modal.id = 'my-modal-W60837'
          const iframe = document.createElement('iframe');
          iframe.src = url;
          const mask = document.createElement('div');
          mask.id = 'my-mask-T90346';
          const navbar = document.createElement('div');
            const leftButtons = document.createElement('div');
              const refreshBtn = document.createElement('button');
              refreshBtn.textContent = '刷新';
              refreshBtn.addEventListener('click', () => { iframe.contentDocument.location.reload(); });
              const continueBtn = document.createElement('button');
              continueBtn.textContent = '继续';
            leftButtons.append(refreshBtn, continueBtn);
            const closeBtn = document.createElement('button');
            closeBtn.textContent = '关闭';
            closeBtn.addEventListener('click', () => { modal.remove(), mask.remove(); });
          navbar.append(leftButtons, closeBtn);
        modal.append(navbar, iframe);
        document.body.append(mask, modal);
        return [() => iframe.contentDocument, refreshBtn, continueBtn, closeBtn];
    };

    const loadHistory = makeExclusive(async () => {
        const targetUrl =
            location.pathname.includes('/installed')
         && confirm("是否导入至当前页面？") && location.toString()
         || prompt("请输入目标页面网址");
        if (targetUrl == null) {
            alert("未输入网址，中止导入"); return;
        }
        alert(
`导入过程中，如遇网址错误、误操作等，需要中止导入的，请直接刷新本页面！
本功能为半自动，请注意跟随按钮高亮配合操作
请等待弹窗页面加载完毕，创建新对话后，点击“继续”开始导入`
        );
        const [document, Brefresh, Bcontinue, Bclose] = createModal(targetUrl);
        const waitTrigger = btn => new Promise((resolve, reject) => {
            const [f, g, h] = [() => {
                btn.classList.remove('my-highlight-L58629');
                Bclose.removeEventListener('click', g);
                btn.removeEventListener('click', h);
            }, () => {
                f(), reject("The modal has been closed prematurely.");
            }, () => {
                f(), resolve();
            }];
            btn.classList.add('my-highlight-L58629');
            Bclose.addEventListener('click', g);
            btn.addEventListener('click', h);
        });
        try {
            await waitTrigger(Bcontinue);
            const text = await readFromLocal();
            if (text == null) {
                alert("读取文件失败，中止导入"); throw "finally";
            }
            const pattern = /(?:您|AI风月)：(.*?)(?=(?:您|AI风月)：|$)/gs;
            const hist = [];
            for (let match; (match = pattern.exec(text)) !== null; hist.push(match[1].trim()));
            const Imsg = () => $('#ai-chat-input', document());
            const Bsend = () => $('#ai-send-button', document());
            const ai_ans = () => (_=>_[_.length-1])($_('#ai-chat-answer', document()));
            while(hist.length) {
                modifyInput(Imsg(), hist.shift(), false, document()), await waitFor(500);
                Bsend().click();
                await waitTrigger(Brefresh);
                await waitTrigger(Bcontinue);
                $$_('button', "编辑", true, ai_ans()).click(), await waitFor(1000);
                const popup = $$_('h3', "编辑", true, document()).parentNode;
                modifyInput($('textarea', popup), hist.shift(), false, document()), await waitFor(500);
                $$_('button', "发送", true, popup).click();
                await waitTrigger(Bcontinue);
            }
            alert("对话记录导入完毕，请按需导入自定义配置");
        } catch(err) {
            if (err === "finally") Bclose.click();
            else showErr(err);
        }
        //let hist = GM_getValue('chat_history', null);
        /*
        if (hist === null) {
            //const text = await multilinePrompt('粘贴对话记录到此处');
            const text = await readFromLocal();
            if (text === null) return;
            const pattern = /(您|AI风月)：(.*?)(?=(?:您|AI风月)：|$)/gs;
            hist = [];
            for (let match; (match = pattern.exec(text)) !== null; hist.push(match[2].trim()));
            GM_setValue('chat_history', hist);
            // console.log('hahaha');
            // console.log(hist);
            $$('.//div[text()="新对话"]').click();
            await waitFor(1000);
            GM_setValue('chat_title', $('div:has(>div[title*="新的对话"]:not(.false)').textContent);
        }
        else {
            // console.log('hey');
            // console.log(hist);
            if (hist.length % 2 != 1) {
                if (confirm('hist length not odd number. Clear local variable?')) clearVar();
                return;
            }
            $(`div[title=${GM_getValue('chat_title')}]`).click();
            await waitFor(1000);
            const ai_ans = (_=>_[_.length-1])($_('#ai-chat-answer'));
            $$('.//button[text()="编辑"]', ai_ans).click();
            await waitFor(1000);
            const popup = $$('.//h3[text()="编辑"]').parentNode;
            modifyInput($('textarea', popup), hist.shift());
            $$('.//button[text()="发送"]', popup).click();
            await waitFor(3000);
        }
        if (!hist.length) {
            clearVar();
            alert('对话记录导入完毕');
            return;
        }
        // console.log('hell')
        // console.log(hist);
        modifyInput($('#ai-chat-input'), hist.shift());
        // console.log('???')
        // console.log(hist);
        GM_setValue('chat_history', hist);
        $('#ai-send-button').click();
        await waitFor(3000);
        location.reload();
        */
    });

(async () => {
    const menu = document.createElement('details');
    menu.className = 'my-highlight-L58629';
    menu.id = 'my-menu-X71368';
    /*☰*/
    menu.innerHTML = '<summary>菜单</summary>';
    const makeItem = (text, action) => {
        const elem = document.createElement('div');
        elem.textContent = text;
        elem.addEventListener('click', () => { menu.open = false; action(); });
        return elem;
    };
    menu.appendChild(makeItem('注册账号', regAccount));
    // if (hist === null) {
    menu.appendChild(makeItem('导入历史记录', loadHistory));
    // }
    // else {
    //  menu.appendChild(makeItem(`继续导入(剩${(hist.length>>1)+1})`, loadHistory));
    //  menu.appendChild(makeItem('取消导入', () => { clearVar(true); }));
    // }
    menu.appendChild(makeItem('隐藏五秒', async () => {
        const ori_dis = menu.style.display;
        menu.open = false;
        menu.style.display = 'none';
        await waitFor(5000);
        menu.style.display = ori_dis;
    }));
    menu.appendChild(makeItem('关闭', () => { menu.remove(); }));
    document.body.appendChild(menu);
})();

})();